package p31_spring的统一异常处理;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.MapUtil;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
import p30_异常处理.MyController;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Map;

/**
 * 原理和_ExceptionResolver差不多，但是定义在ControllerAdvice中的异常处理方法是全局的
 * 如果异常，在控制器中有对应的异常处理方法，就优先使用控制器方法内部的，否则就会使用全局的
 */
public class _ExceptionResolverControllerAdvice {
    public static void main(String[] args) throws NoSuchMethodException {
        MockHttpServletRequest request  = new MockHttpServletRequest();
        MockHttpServletResponse response = new MockHttpServletResponse();
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(WebConfig.class);
        ExceptionHandlerExceptionResolver resolver = context.getBean("resolver", ExceptionHandlerExceptionResolver.class);

        HandlerMethod handlerMethod = new HandlerMethod(new MyController(), MyController.class.getMethod("foo"));
        IOException e = new IOException("23333");
        resolver.resolveException(request, response, handlerMethod, e);
        System.out.println(new String(response.getContentAsByteArray()));
    }

    @Configuration
    static class WebConfig {
        @ControllerAdvice
        static class MyControllerAdvice {
            @ExceptionHandler
            @ResponseBody
            public Map handler(IOException e, HttpServletRequest request) {
                System.out.println(request);
                return MapUtil.of("error", e.getMessage());
            }
        }

        @Bean("resolver")
        public ExceptionHandlerExceptionResolver resolver() {
            /**
             * ExceptionHandlerExceptionResolver在初始化时(afterPropertiesSet方法)，会从容器中找到所有@ControllerAdvice修饰的bean
             * 然后找到这些bean中所有加了@ExceptionHandler的方法，存入缓存
             * RequestMappingHandlerAdapter在初始化时也有类似的步骤
             */
            ExceptionHandlerExceptionResolver resolver = new ExceptionHandlerExceptionResolver();
            resolver.setMessageConverters(ListUtil.of(new MappingJackson2HttpMessageConverter()));
            return resolver;
        }
    }

}
